﻿using System.Diagnostics;
using DotNet.Common;
using System.Windows.Forms;
using System;

namespace TextCmd
{
	class Commander
	{
		Process m_cmdProcess;
		string m_cmdFilepath;
		bool m_startFlag;
		bool m_breakFlag;
		int m_cmdProcessID;

		public event StringInvoker OnOutputData;
		public event MethodInvoker OnRunStart;
		public event MethodInvoker OnRunStop;

		public void Load(string cmdFilepath)
		{
			m_cmdFilepath = cmdFilepath;
			StartCmdProcess();
		}

		public void UnLoad()
		{
			KillAllProcess();
		}

		private void StartCmdProcess()
		{
			try
			{
				m_cmdProcess = new Process();
				m_cmdProcess.StartInfo.UseShellExecute = false;
				m_cmdProcess.StartInfo.RedirectStandardInput = true;
				m_cmdProcess.StartInfo.RedirectStandardError = true;
				m_cmdProcess.StartInfo.RedirectStandardOutput = true;
				m_cmdProcess.StartInfo.CreateNoWindow = true;
				m_cmdProcess.StartInfo.FileName = m_cmdFilepath;
				m_cmdProcess.OutputDataReceived += cmdProcess_OutputDataReceived;
				m_cmdProcess.ErrorDataReceived += cmdProcess_OutputDataReceived;

				m_cmdProcess.Start();
				m_cmdProcess.BeginOutputReadLine();
				m_cmdProcess.BeginErrorReadLine();
				m_breakFlag = false;
				m_cmdProcessID = m_cmdProcess.Id;
			}
			catch (Exception e)
			{
				OutputData(e.Message);
			}
		}

		/// <summary>
		/// 启动命令行
		/// </summary>
		/// <param name="cmd"></param>
		public void Run(string cmd)
		{
			if (cmd.Length == 1)
			{
				if (char.IsControl(cmd[0]))
				{
					switch (cmd[0])
					{
						case '\x3':
							if (!m_breakFlag)
							{
								OutputData("[Ctrl + C]User Breaked!");
								if (!m_cmdProcess.HasExited)
								{
									m_cmdProcess.CancelOutputRead();
									m_cmdProcess.CancelErrorRead();
									m_cmdProcess.Close();
								}
								m_breakFlag = true;
								if (OnRunStop != null)
									OnRunStop();
							}
							break;
					}
					return;
				}
			}

			OutputData("\r\n");

			if (m_breakFlag || m_cmdProcess.HasExited)
			{
				KillAllProcess();
				StartCmdProcess();
			}

			if (!StartProcess(cmd))
			{
				if (OnRunStart != null)
				{
					OnRunStart();
				}
				m_startFlag = true;
				m_cmdProcess.StandardInput.WriteLine(cmd);
			}
		}

		void cmdProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
		{
			OutputData(e.Data);

			if (m_startFlag)
			{
				if (OnRunStop != null)
				{
					OnRunStop();
				}
				if (!string.IsNullOrEmpty(e.Data))
				{
					m_startFlag = false;
				}
			}
		}

		void OutputData(string str)
		{
			try
			{
				if (OnOutputData != null && str != null)
				{
					OnOutputData(str);
				}
			}
			catch
			{
				
			}
		}

		bool StartProcess(string filename)
		{
			try
			{
				Process oNewProcess = new Process();
				oNewProcess.StartInfo.FileName = filename;
				oNewProcess.StartInfo.UseShellExecute = false;
				oNewProcess.StartInfo.RedirectStandardOutput = true;
				oNewProcess.StartInfo.RedirectStandardError = true;
				oNewProcess.OutputDataReceived += cmdProcess_OutputDataReceived;
				oNewProcess.ErrorDataReceived += cmdProcess_OutputDataReceived;
				if (oNewProcess.Start())
				{
					oNewProcess.BeginOutputReadLine();
					oNewProcess.BeginErrorReadLine();
					return true;
				}
				else
				{
					return false;
				}
			}
			catch (Exception e)
			{
				Debug.WriteLine(e.Message);
				return false;
			}
		}

		void KillAllProcess()
		{
			try
			{
				if (m_cmdProcessID > 0)
				{
					Process oNewProcess = new Process();
					oNewProcess.StartInfo.FileName = "taskkill";
					oNewProcess.StartInfo.Arguments = string.Format("/PID {0} /F /T", m_cmdProcessID);
					oNewProcess.StartInfo.UseShellExecute = false;
					oNewProcess.StartInfo.CreateNoWindow = true;
					oNewProcess.Start();
				}
			}
			catch (Exception e)
			{
				Debug.WriteLine(e);
			}
		}
	}
}
